package com.xyy.saas.payment.merchant.core.service;

import com.xyy.saas.payment.adpater.RouteManager;
import com.xyy.saas.payment.api.impl.PaymentOrderApiImpl;
import com.xyy.saas.payment.callback.core.result.CallbackRunner;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.RocketMqTopic;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.SeparateAccountsBo;
import com.xyy.saas.payment.cores.bo.UserBo;
import com.xyy.saas.payment.cores.enums.BusinessIdTypeEnum;
import com.xyy.saas.payment.cores.enums.BusinessTypeEnum;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.cores.vo.SeparateAccountFromUserVo;
import com.xyy.saas.payment.dao.model.ApplyBankcardModify;
import com.xyy.saas.payment.dao.model.PayAccount;
import com.xyy.saas.payment.dao.model.ThirdUserInfo;
import com.xyy.saas.payment.merchant.core.dto.QueryAccountDto;
import com.xyy.saas.payment.merchant.core.dto.RegisterOrderDto;
import com.xyy.saas.payment.merchant.core.vo.UserInfoVo;
import com.xyy.saas.payment.payment.core.service.ProfitSharingService;
import com.xyy.saas.payment.service.ApplyBankcardModifyService;
import com.xyy.saas.payment.service.PayAccountService;
import com.xyy.saas.payment.service.ThirdUserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;

@Service
@Slf4j
public class FBank2PinganMoveService {
    @Resource
    private PayAccountService payAccountService;
    @Resource
    private ThirdUserInfoService thirdUserInfoService;
    @Resource
    private RouteManager routeManager;
    @Resource
    private PaymentOrderApiImpl paymentOrderApi;
    @Resource
    private SeparateOrderService2 separateOrderService2;
    @Resource
    private ProfitSharingService profitSharingService;
    @Resource
    private UserInfoService2 userInfoService2;
    @Resource
    private ApplyBankcardModifyService applyBankcardModifyService;
    @Resource
    private CallbackRunner callbackRunner;

    /**
     * 迁移
     *  1.富民商户冻结余额解冻
     *  2.富民商户可提现余额清空(富民商户可提现余额->富民平台可提现余额)
     *  3.平安商户可提现余额初始化，初始化金额必须等于富民可提现清空余额
     *  4.平安商户替换富民商户
     *   4.1 pay_account
     *   4.2 user_info
     *   4.3 third_user_info
     *   4.4 apply_bankcard_modify
     */
    public void move(String businessIdType, String fromBusinessId, String toBusinessId) throws PaymentException {
        log.info("FBank2PinganMoveService#move start. businessIdType={}, fromBusinessId={}, toBusiness={}",
                businessIdType, fromBusinessId, toBusinessId);
        // 0.查询支付平台信息
        PayAccount fBankPayAccount = payAccountService.selectByBusiness(businessIdType, fromBusinessId);
        PayAccount pinganPayAccount = payAccountService.selectByBusiness(businessIdType, toBusinessId);

        if(fBankPayAccount == null || pinganPayAccount == null) {
            throw new PaymentException(ResultCodeEnum.USER_NOT_FOUND);
        }

        // 0.查询渠道信息
        ThirdUserInfo fBankThirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(fBankPayAccount.getAccountId());
        ThirdUserInfo pinganThirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(pinganPayAccount.getAccountId());

        if(fBankThirdUserInfo == null || pinganThirdUserInfo == null)  {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST);
        }

        UserBo fBankBalance = routeManager.queryAccount(QueryAccountDto.
                build(businessIdType, fBankPayAccount.getAccountId(), fBankThirdUserInfo.getThirdUserId()));

        if(fBankBalance.getWithdrawableBalance() > NumberUtils.INTEGER_ZERO) {
            try {
                // 1.富民商户可提现余额清空(富民商户可提现余额->富民平台可提现余额)
                SeparateAccountFromUserVo merchant2platform = new SeparateAccountFromUserVo();
                merchant2platform.setBusinessOrderNo(fBankPayAccount.getBusinessUserId() + "_clear_withdraw_amount"); // 商户标识作为转账单号
                merchant2platform.setBusinessType(BusinessTypeEnum.EC.getType());
                merchant2platform.setBusinessIdType(BusinessIdTypeEnum.EC_POP.getType());
                merchant2platform.setBusinessOrderType(BusinessIdTypeEnum.EC_POP.getType());

                merchant2platform.setBusinessUserIdOut(fBankPayAccount.getBusinessUserId());
                merchant2platform.setBusinessUserIdIn("ec_pop_platform");
                merchant2platform.setAmount(fBankBalance.getWithdrawableBalance().intValue());

                merchant2platform.setInvoker(StringUtils.EMPTY);
                merchant2platform.setExtra("富民商户可提现余额清空（商户->平台）");
                ResultVO<SeparateAccountsBo> fBankTransfer = paymentOrderApi.separateAccountFromUser(merchant2platform, StringUtils.EMPTY);

                if(!ResultCodeEnum.SUCCESS.getCode().equals(fBankTransfer.getCode())) {
                    throw new PaymentException(fBankTransfer.getDisplayMsg());
                }

                // 2.平安商户可提现余额初始化，初始化金额必须等于富民可提现清空余额
                separateOrderService2.registerOrder(RegisterOrderDto.builder().
                        businessIdType(businessIdType).
                        accountId(pinganPayAccount.getAccountId()).
                        businessOrderNo(pinganPayAccount.getBusinessUserId()).
                        amount(fBankBalance.getWithdrawableBalance().intValue()).build());
            }
            catch(Exception ex) {
                log.error(ex.getMessage() + ", move fail for WithdrawableBalance. fromBusinessId="
                        + fromBusinessId + ", toBusinessId=" + toBusinessId, ex);
            }
        }

        /**
         * 3.平安商户替换富民商户
         *  3.1 pay_account
         *  3.2 user_info
         *  3.3 third_user_info
         *  3.4 apply_bankcard_modify
         */
        String fBankAccountId = fBankPayAccount.getAccountId();
        String fBankBusinessId = fBankPayAccount.getBusinessUserId();
        String pinganAccountId = pinganPayAccount.getAccountId();

        // 3.1 pay_account
        fBankPayAccount.setAccountId(fBankAccountId + PayAccount.SUFFIX_DELETE);
        fBankPayAccount.setBusinessUserId(fBankBusinessId + PayAccount.SUFFIX_DELETE);
        payAccountService.updateByPrimaryKeySelective(fBankPayAccount);

        pinganPayAccount.setAccountId(fBankAccountId);
        pinganPayAccount.setBusinessUserId(fBankBusinessId);
        payAccountService.updateByPrimaryKeySelective(pinganPayAccount);

        // 3.2 user_info
        UserInfoVo fBankUserInfoVo = userInfoService2.queryUserInfo(fBankAccountId);
        fBankUserInfoVo.setAccountId(fBankAccountId + PayAccount.SUFFIX_DELETE);
        userInfoService2.updateUserInfo(fBankUserInfoVo);

        UserInfoVo pinganUserInfoVo = userInfoService2.queryUserInfo(pinganAccountId);
        pinganUserInfoVo.setAccountId(fBankAccountId);
        userInfoService2.updateUserInfo(pinganUserInfoVo);

        // 3.3 third_user_info
        fBankThirdUserInfo.setUserId(fBankAccountId + PayAccount.SUFFIX_DELETE);
        thirdUserInfoService.updateByPrimaryKeySelective(fBankThirdUserInfo);

        pinganThirdUserInfo.setUserId(fBankAccountId);
        thirdUserInfoService.updateByPrimaryKeySelective(pinganThirdUserInfo);

        // 3.4 apply_bankcard_modify
        List<ApplyBankcardModify> applyBankcardModifies = applyBankcardModifyService.
                queryApplyInfoListByAccountId(pinganAccountId, StringUtils.EMPTY);

        if(!CollectionUtils.isEmpty(applyBankcardModifies)) {
            applyBankcardModifies.forEach(applyBankcardModify -> {
                applyBankcardModify.setAccountId(fBankAccountId);

                if(Constants.SOURCE_OPEN_ACCOUNT.equals(applyBankcardModify.getSource())) {
                    applyBankcardModify.setBusinessOrderNo(fBankBusinessId);
                }

                applyBankcardModifyService.updateByPrimary(applyBankcardModify);
            });
        }

        // 4.异步处理富民冻结金额
        callbackRunner.syncSendMsg(RocketMqTopic.TOPIC_FM_FROZEN_AMOUNT_HANDLE, fBankAccountId + PayAccount.SUFFIX_DELETE);
    }
}
